#!/home/dt/anaconda3/envs/JuHua/bin python3
import os
import re
import sys
import threading
import time
import cv2
from PySide6 import QtCore, QtWidgets
from PySide6.QtWidgets import QMainWindow, QWidget, QVBoxLayout, QApplication, QSlider, QPushButton, QFileDialog, \
    QHBoxLayout, QFrame, QMessageBox, QLabel, QLayout
from PySide6.QtGui import QAction, QPalette, QColor, QImage, QPixmap
from PySide6.QtCore import Qt, QObject, Signal, QThread, QMargins

from LogWindow import LogWindow
from constants import *
from ui_Ptfe import Ui_Paraffin
import resource.rc_resource
from backendWorker import BackendWorker

sys.path.append("./MvImport")
from MvImport.MvCameraControl_class import *
from loguru import logger
import numpy as np

class ImageUpdateSignal(QObject):
    # 定义一个信号，传递QPixmap对象
    pixmap_signal = Signal(QPixmap, object)


class MediaPlayer(QWidget, Ui_Paraffin):
    deviceList = MV_CC_DEVICE_INFO_LIST()
    tlayerType = MV_GIGE_DEVICE | MV_USB_DEVICE
    # 定义发送到工作线程的信号
    toWorkerSignal = Signal(dict)

    def __init__(self):
        super(MediaPlayer, self).__init__()
        self.setupUi(self)
        self.frame_status.installEventFilter(self)
        self.frame_status.setParent(self.label_monitor)
        self.init()
        self.worker = BackendWorker()
        self.thread = QThread()
        # 将工作线程移动到新线程
        self.worker.moveToThread(self.thread)
        self.btn_log.clicked.connect(self.open_log)
        # 连接信号和槽
        self.toWorkerSignal.connect(self.worker.processMainThreadMessage)
        self.worker.toMainThreadSignal.connect(self.handleWorkerMessage)
        # 启动线程
        self.thread.start()

    def init(self):
        self.log_window = LogWindow()
        self.cameras = [MvCamera()]  # 创建相机实例
        self.image_update_signal = ImageUpdateSignal()
        # 连接信号到更新UI的槽函数
        self.image_update_signal.pixmap_signal.connect(self.update_image)

        qss = QtCore.QFile(":/qss/Paraffin.qss")
        qss.open(QtCore.QIODevice.ReadOnly)
        self.setStyleSheet(str(qss.readAll(), 'utf-8'))
        self.btn_close.clicked.connect(self.close)

        self.label_monitor.setScaledContents(True)  # 图片自适应

    def resizeEvent(self, event):
        self.frame_status.setFixedWidth(self.label_monitor.width())
        self.frame_status.move(0, self.label_monitor.height() - self.frame_status.height())

    def setStatusNormal(self, mlabel):
        mlabel.setProperty("status", ParaffinStatus.NORMAL)
        self.style().polish(mlabel)

    def setStatusLow(self, mlabel):
        mlabel.setProperty("status", ParaffinStatus.LOW)
        self.style().polish(mlabel)

    def handleWorkerMessage(self, message):
        logger.info(f"Main thread received message from worker: {message}")
        # type = message["type"]
        ratio = message["ratio"]
        pattern_ratio = r'(\d+):(\d+)'
        match_ratio = re.match(pattern_ratio, ratio)
        ptfe = match_ratio.group(1)
        water = int(match_ratio.group(2))

        speed = message["speed"]
        pattern_speed = r"(\d+(?:\.\d+)?)m/s"
        match_speed = re.match(pattern_speed, speed)
        speed_num = int(match_speed.group(1))

        self.label_ratio_value.setText(ratio)
        self.label_speed_value.setText(speed)

        if water < 4:
            self.label_ratio_status.setText(f"比例过低")
            logger.info(f"PTFE颗粒与水比例过低：{ratio}")
            self.setStatusLow(self.frame_ratio)
        else:
            self.label_ratio_status.setText(f"比例正常")
            self.setStatusNormal(self.frame_ratio)
        if speed_num < 3:
            self.label_speed_status.setText(f"流速过低")
            logger.info(f"流速过低：{speed}")
            self.setStatusLow(self.frame_speed)
        else:
            self.label_speed_status.setText(f"流速正常")
            self.setStatusNormal(self.frame_speed)


    # def mute(self):
    #     logger.info("mute")
    #     self.toWorkerSignal.emit({"type": Constants.TYPE_MUTE, "mutetime" : 30})
    #

    def open_log(self):
        self.log_window.fill_table('./logs')
        self.log_window.setWindowModality(Qt.WindowModality.ApplicationModal)
        self.log_window.show()
        self.toWorkerSignal.emit({"type": Constants.TYPE_LOG})

    def alarm(self):
        logger.info("alarm")
        self.toWorkerSignal.emit({"type": Constants.TYPE_ALARM, 'alarmtime' : 10})

    def exception(self):
        logger.info("exception")
        self.toWorkerSignal.emit({"type": Constants.TYPE_EXCEPTION})



    def update_status(self, label, status):
        label.setProperty("status", status)
        self.style().polish(label)

    def update_image(self, pixmap, label):
        # 在这个槽函数中更新label的pixmap
        pix = pixmap.scaled(label.width(), label.height(), Qt.KeepAspectRatio, Qt.SmoothTransformation)
        label.setPixmap(pix)


    def work_thread(self, index, cam, pData, nDataSize, label):
        stFrameInfo = MV_FRAME_OUT_INFO_EX()
        memset(byref(stFrameInfo), 0, sizeof(stFrameInfo))
        n = 1
        while True:
            ret = cam.MV_CC_GetOneFrameTimeout(pData, nDataSize, stFrameInfo, 1000)
            if ret == 0:
                image = np.asarray(pData)
                image = image.reshape((stFrameInfo.nHeight, stFrameInfo.nWidth, 1))
                image = cv2.cvtColor(image, cv2.COLOR_BAYER_GB2BGR)
                # print(type(image))

                # 发送图片给工作线程
                if n % 10 == 0:
                    self.toWorkerSignal.emit({"index":index, "image":image})
                n = (n + 1) % 10000

                image_height, image_width, image_depth = image.shape
                image_show = QImage(image.data, image_width, image_height, image_width * image_depth,
                                    QImage.Format_RGB888)
                pixmap = QPixmap.fromImage(image_show)
                # 发射信号，传递pixmap和label给槽函数
                self.image_update_signal.pixmap_signal.emit(pixmap, label)

            if self.g_bExit == True:
                del pData
                break

    def get_camera_information(self):
        ret = MvCamera.MV_CC_EnumDevices(self.tlayerType, self.deviceList)
        logger.info(self.deviceList.nDeviceNum)
        if ret != 0:
            logger.info("enum devices fail! ret[0x%x]" % ret)
            QMessageBox.critical(self, '错误', '读取设备驱动失败！')
            # sys.exit()
        if self.deviceList.nDeviceNum == 0:
            QMessageBox.critical(self, "错误", "没有发现设备 ！ ")
            logger.info("find no device!")
            # sys.exit()
        else:
            # QMessageBox.information(self, "提示", "发现了 %d 个设备 !" % self.deviceList.nDeviceNum)
            logger.info("Find %d devices!" % self.deviceList.nDeviceNum)
        if self.deviceList.nDeviceNum == 0:
            return None

        self.camera_information = True

    def open_single_camera(self, camera_index):
        cam = self.cameras[camera_index]
        self.g_bExit = False
        # 选择设备并创建句柄
        stDeviceList = cast(self.deviceList.pDeviceInfo[int(camera_index)], POINTER(MV_CC_DEVICE_INFO)).contents
        ret = cam.MV_CC_CreateHandle(stDeviceList)
        if ret != 0:
            QMessageBox.critical(self, "错误", "创建句柄失败 ! ret[0x%x]" % ret)
            return False, None, None

        # 打开设备
        ret = cam.MV_CC_OpenDevice(MV_ACCESS_Exclusive, 0)
        if ret != 0:
            logger.info("open device fail! ret[0x%x]" % ret)
            QMessageBox.critical(self, "错误", "打开设备失败 ! ret[0x%x]" % ret)
            return False, None, None

        # 探测网络最佳包大小(只对GigE相机有效)
        if stDeviceList.nTLayerType == MV_GIGE_DEVICE:
            nPacketSize = cam.MV_CC_GetOptimalPacketSize()
            if int(nPacketSize) > 0:
                ret = cam.MV_CC_SetIntValue("GevSCPSPacketSize", nPacketSize)
                if ret != 0:
                    logger.warning("Warning: Set Packet Size fail! ret[0x%x]" % ret)
                    QMessageBox.warning(self, "警告", "报文大小设置失败 ! ret[0x%x]" % ret)
            else:
                logger.warning("Warning: Get Packet Size fail! ret[0x%x]" % nPacketSize)
                QMessageBox.warning(self, "警告", "报文大小获取失败 ! ret[0x%x]" % nPacketSize)

        # 设置触发模式为off
        ret = cam.MV_CC_SetEnumValue("TriggerMode", MV_TRIGGER_MODE_OFF)
        if ret != 0:
            logger.warning("set trigger mode fail! ret[0x%x]" % ret)
            QMessageBox.critical(self, "错误", "设置触发模式失败 ! ret[0x%x]" % ret)
            return False, None, None

        # 获取数据包大小
        stParam = MVCC_INTVALUE()
        memset(byref(stParam), 0, sizeof(MVCC_INTVALUE))
        ret = cam.MV_CC_GetIntValue("PayloadSize", stParam)
        if ret != 0:
            logger.warning("get payload size fail! ret[0x%x]" % ret)
            QMessageBox.critical(self, "错误", "获取有效负载大小失败 ! ret[0x%x]" % ret)
            return False, None, None
        nPayloadSize = stParam.nCurValue

        # 开始取流
        ret = cam.MV_CC_StartGrabbing()
        if ret != 0:
            logger.warning("start grabbing fail! ret[0x%x]" % ret)
            QMessageBox.critical(self, "错误", "开始抓取图像失败 ! ret[0x%x]" % ret)
            return False, None, None

        data_buf = (c_ubyte * nPayloadSize)()
        return True, data_buf, nPayloadSize

    # 打开摄像头。
    def openCamera(self):
        self.get_camera_information()
        if self.camera_information == True:
            # camera_count = self.deviceList.nDeviceNum
            camera_count = min(1, self.deviceList.nDeviceNum)
            for index in range(camera_count):
                success, data_buf, nPayloadSize = self.open_single_camera(index)
                if not success:
                    QMessageBox.critical(self, '错误', f'打开相机{index}失败！')
                    continue  # 或者根据你的需求选择是否退出
                # try:
                logger.info("启动线程：" + str(index))
                thread = threading.Thread(target=self.work_thread,
                                          args=(
                                        # lm:添加index
                                          index, self.cameras[index], data_buf, nPayloadSize, self.label_monitor))
                thread.daemon = True
                thread.start()
                # except:
                #     logger.error("error: unable to start thread")
                #     QMessageBox.critical(self, "错误", "无法启动线程 ! ")
        else:
            QMessageBox.critical(self, '错误', '获取相机信息失败！')
            return None

def main():
    nowtime = time.strftime("%Y-%m-%d", time.localtime())
    logger.add(
        f'logs/Ptfe_{nowtime}.log',  # 日志文件路径
        format='{time:YYYY-MM-DD HH:mm:ss} |<lvl>{level:8}</>| {name} : {module}:{line:4} | <cyan>mymodule</> | - <lvl>{message}</>',
        rotation="1 day",  # 每天旋转日志文件
        compression="zip",  # 压缩日志文件
        # retention="3 months"  # 保留3个月的日志文件
    )
    app = QApplication(sys.argv)
    player = MediaPlayer()
    player.show()
    player.showFullScreen()
    player.openCamera()
    sys.exit(app.exec())


if __name__ == "__main__":
    main()
